'use strict'

// Web request completed 监听
class WebRequestCompletedListener {
  // 构造器
  constructor () {
    // 初始化私有变量
    // -  匹配规则 default
    this.urlMatchRules = [{
      action: 'addButton@taobao',
      type: 'xmlhttprequest',
      match: 'trade.taobao.com/trade/itemlist/asyncSold.htm',
      url: null,
      origin: null,
      pathname: null
    }]
    // 截获所有网络请求
    chrome.webRequest.onCompleted.addListener((details) => {
      const tabId = details.tabId
      // 如果是来自background的请求则无视掉
      if (tabId === -1) return
      // 注册资源请求状态完成 广播通知 xmlhttprequest
      this.urlMatchRules.forEach(rule => {
        let isMatching = false
        // 正则匹配
        if (rule.match && new RegExp(rule.match).test(details.url)) {
          isMatching = true
        }
        // url匹配
        if (rule.url && rule.url === details.url) {
          isMatching = true
        }
        // origin&pathname批量
        if ((rule.origin || rule.pathname) &&
            new RegExp([rule.origin, rule.pathname].filter(e => !!e).join('').replace(/\//g, '\\/')).test(details.url)) {
          isMatching = true
        }
        // 类型不匹配则直接终止
        if (rule.type && (rule.type !== details.type)) {
          isMatching = false
        }
        isMatching && chrome.tabs.sendMessage(tabId, {
          action: rule.action,
          detail: details
        })
      })
    }, {
      urls: ['<all_urls>']
      // urls: ["http://*/*", "https://*/*"],
      // types: ["xmlhttprequest"]
    }
    )
  }

  // 监听器
  addRule (options) {
    this.urlMatchRules.find(e => {
      return e.action === options.action &&
        e.type === options.type &&
        e.match === options.match
    }) || this.urlMatchRules.push(options)
  }
}

const requestCompletedListener = new WebRequestCompletedListener()

// Web request header 修改
class WebRequestHeaderModification {
  // 构造器
  constructor () {
    // 初始化私有变量
    // -  匹配规则 default
    this.urlMatchRules = []
    // 截获所有网络请求
    chrome.webRequest.onBeforeSendHeaders.addListener((details) => {
      const tabId = details.tabId
      // 如果是来自background的请求则无视掉
      if (tabId === -1) {
        this.urlMatchRules.forEach(rule => {
          // 检查URL
          if (rule.match && !new RegExp(rule.match).test(details.url)) return
          // 检查类型
          if (rule.type && (rule.type !== details.type)) return
          // 完成检查后修改header
          Object.keys(rule.headers).forEach(key => {
            const exist = details.requestHeaders.find(e => e.name.toLocaleLowerCase() === key.toLowerCase())
            if (exist) {
              exist.value = rule.headers[key]
            } else {
              details.requestHeaders.push({
                name: key,
                value: rule.headers[key]
              })
            }
          })
        })
      }
      return { requestHeaders: details.requestHeaders }
    }, {
      urls: ['<all_urls>']
      // urls: ["http://*/*", "https://*/*"],
      // types: ["xmlhttprequest"]
    }, ['blocking', 'requestHeaders']
    )
  }

  // 添加规则
  addRule (rule) {
    this.urlMatchRules.find(e => {
      return JSON.stringify(e.headers) === JSON.stringify(rule.headers) &&
        e.type === rule.type &&
        e.match === rule.match
    }) || this.urlMatchRules.push(rule)
  }
}

const webHeaderMod = new WebRequestHeaderModification()

// DOM Loaded 监听
class PageLoadListener {
  // 构造器
  constructor () {
    // 初始化私有变量
    // -  匹配规则 default
    this.urlMatchRules = [{
      action: 'addButton@taobao',
      match: 'trade.taobao.com/trade/itemlist/list_sold_items.htm',
      type: 'DOMContentLoaded'
    }]
    // 监听页面DOM构造完毕
    chrome.webNavigation.onDOMContentLoaded.addListener(details => {
      const tabId = details.tabId
      // 订单页面换页 xmlhttprequest
      this.urlMatchRules.forEach(rule => {
        if (rule.type !== 'DOMContentLoaded') return
        // 如果正则存在并且不匹配则匹配失败
        if (rule.match && !new RegExp(rule.match).test(details.url)) {
          return
        }
        chrome.tabs.sendMessage(tabId, {
          action: rule.action,
          detail: details
        })
      })
    })
    // 监听页面DOM&资源加载完毕
    chrome.webNavigation.onCompleted.addListener(details => {
      const tabId = details.tabId
      // 订单页面换页 xmlhttprequest
      this.urlMatchRules.forEach(rule => {
        if (rule.type !== 'Completed') return
        // 如果正则存在并且不匹配则匹配失败
        if (rule.match && !new RegExp(rule.match).test(details.url)) {
          return
        }
        chrome.tabs.sendMessage(tabId, {
          action: rule.action,
          detail: details
        })
      })
    })
  }

  // 监听器
  addRule (options) {
    this.urlMatchRules.find(e => {
      return e.action === options.action &&
        e.type === options.type &&
        e.match === options.match
    }) || this.urlMatchRules.push(options)
  }
}

const pageLoadListener = new PageLoadListener()

// 数据中介仓库
class DataCabinet {
  // 构造器
  constructor () {
    this.library = {}
  }

  // 放入数据
  put (data, takeCode) {
    if (typeof this.library[takeCode] === 'undefined') {
      this.library[takeCode] = {
        data: data,
        takeCode: takeCode
      }
      return true
    }
    return false
  }

  // 取出数据
  take (takeCode) {
    if (typeof this.library[takeCode] !== 'undefined') {
      const unit = this.library[takeCode]
      // delete this.library[takeCode];
      return unit.data
    }
    return undefined
  }
}

const dataCabinet = new DataCabinet()

// Cross Page RPC
class RPCAgent {
  // 构造器
  constructor () {
    this.services = []
    this.serviceTasks = []

    // 与服务提供者保持连接提供服务
    chrome.runtime.onConnect.addListener(port => {
      port.onMessage.addListener(request => {
        if (request.action !== 'RPC_AGENT') return

        if (request.method === 'SERVER_REGISTER_SERVICE') {
          this.registerService({
            name: request.name,
            port: port
          })
          return
        }

        if (request.method === 'SERVER_RESPONSE_SERVICE') {
          const task = this.serviceTasks.find(task => task.procedureId === request.procedureId)
          task.callback(request.params, request.procedureId)
          this.serviceTasks = this.serviceTasks.filter(task => task.procedureId !== request.procedureId)
          return
        }

        if (request.method === 'CLIENT_CALL_SERVICE') {
          this.callService({
            name: request.name,
            callback: (params, procedureId) => {
              port.postMessage({
                action: 'RPC_CLIENT',
                method: 'AGENT_RESPONSE_SERVICE',
                params: params,
                procedureId: procedureId
              })
            },
            params: request.params,
            procedureId: request.procedureId
          })
        }
      })
    })
  }

  /**
   * 注册服务
   * @param newService
   * @param newService.name
   * @param newService.port
   */
  registerService (newService) {
    const service = this.services.find(service => service.name === newService.name)
    if (service) {
      service.port = newService.port
    } else {
      this.services.push(newService)
    }
  }

  //
  /**
   * 调用服务
   * @param serviceCall
   * @param serviceCall.name
   * @param serviceCall.params
   * @param serviceCall.callback
   * @param serviceCall.procedureId
   */
  callService (serviceCall) {
    const service = this.services.find(service => service.name === serviceCall.name)
    if (!service) return
    const task = {
      callback: serviceCall.callback,
      procedureId: serviceCall.procedureId
    }
    // 记录任务
    this.serviceTasks.push(task)
    console.log(serviceCall)
    // 任务开始
    service.port.postMessage({
      action: 'RPC_SERVER',
      method: 'AGENT_CALL_SERVICE',
      procedureId: task.procedureId,
      name: serviceCall.name,
      params: serviceCall.params
    })
  }
}

RPCAgent.procedureIdInc = 0
const rpcServer = new RPCAgent()
console.log('rpcServer initialized', rpcServer)

// 事件消息监听
chrome.runtime.onMessage.addListener(function name (request, sender, sendResponse) {
  // action - xhr 加载代理
  if (request.action === 'ajax') {
    const options = request.data
    options.success = function (data, textStatus, jqXHR) {
      sendResponse({
        success: true,
        data: data,
        textStatus: textStatus,
        jqXHR: jqXHR
      })
    }
    options.error = function (jqXHR, textStatus, errorThrown) {
      sendResponse({
        success: false,
        jqXHR: jqXHR,
        textStatus: textStatus,
        errorThrown: errorThrown
      })
    }
    if (options.fakeHeaders) {
      // 添加一个默认规则
      webHeaderMod.addRule({
        type: 'xmlhttprequest',
        url: options.url,
        origin: options.origin,
        pathname: options.pathname,
        match: options.match,
        headers: options.fakeHeaders
      })
    }
    // eslint-disable-next-line no-undef
    ($ || {}).ajax(options)
  }
  // action - web request listener
  if (request.action === 'addWebRequestCompletedListener') {
    requestCompletedListener.addRule(request.data)
  }
  // action - pageLoad listener
  if (request.action === 'pageLoadListener') {
    // 页面加载完毕
    pageLoadListener.addRule(request.data)
  }
  // action - data agent
  if (request.action === 'dataCabinetPut') {
    sendResponse(dataCabinet.put(request.data, request.takeCode))
  }
  if (request.action === 'dataCabinetTake') {
    sendResponse(dataCabinet.take(request.takeCode))
  }

  return true
})
